package com.wonders.hs.pd.mm.web.message;

import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.annotation.OnConnect;
import com.corundumstudio.socketio.annotation.OnDisconnect;
import com.corundumstudio.socketio.annotation.OnEvent;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.wonders.hs.pd.mm.web.bean.MessageInfo;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Component;

import java.io.*;
import java.nio.file.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import static java.nio.file.StandardWatchEventKinds.OVERFLOW;

/**
 * @author banglong on 2017/2/4.
 */
@Component
public class MessageHandler {

  private static final Logger logger = LoggerFactory.getLogger(MessageHandler.class);

  private static SocketIOServer server;

  // 当前的 信息对象
  public static MessageInfo currentMsg;
  // 当前的 延时任务对象
  private static Timer timer;
  // 开始时间
  private static Date startTime = null;
  // 结束时间
  private static Date endTime = null;


  @Autowired
  public MessageHandler(SocketIOServer socketIOServer) {
    server = socketIOServer;
  }

  // 连接时调用
  @OnConnect
  public void onConnect(SocketIOClient client) {
    Date now = new Date();
    if (currentMsg.isPublic() && startTime != null && endTime != null
            && (endTime.getTime() - startTime.getTime()) > 0
            // 当前时间在 开始时间 和 结束时间之间才能推送
            && (startTime.getTime() - now.getTime()) < 0
            && (endTime.getTime() - now.getTime()) > 0) {
      client.sendEvent("messageevent", currentMsg);
    }
  }

  @OnDisconnect
  public void onDisconnect(SocketIOClient client) {
  }

  // 消息接收入口
  @OnEvent(value = "messageevent")
  public void onEvent(SocketIOClient client, AckRequest request, MessageInfo messageInfo) {
//        logger.info(messageInfo.getMsgContent());
  }

  // 给所有客户端发送消息
  public static void sendMessageForAll(MessageInfo messageInfo) {
    if (messageInfo != null) {
      Collection<SocketIOClient> allClients = server.getAllClients();
      for (SocketIOClient client : allClients) {
        client.sendEvent("messageevent", messageInfo);
      }
    }
  }

  // 需要对文件进行监听
  public static void watchMsgFile() {
    File messageFile = getMessageFile();

    // 执行定时任务
    currentMsg = getMsgInfoByFile(messageFile);
    if (currentMsg != null) {
      task(currentMsg);
    }

    // 监听文件
    if (messageFile != null) {
      Path path = Paths.get(messageFile.getParentFile().getAbsolutePath());
      try {
        final WatchService watchService = path.getFileSystem().newWatchService();
        path.register(watchService, StandardWatchEventKinds.ENTRY_MODIFY);
        while (true) {
          WatchKey key = watchService.take();
          for (WatchEvent<?> event : key.pollEvents()) {
            WatchEvent.Kind kind = event.kind();

            // 事件可能lost or discarded
            if (kind == OVERFLOW) {
              continue;
            }

            // 执行定时任务
            currentMsg = getMsgInfoByFile(getMessageFile());
            if (currentMsg != null) {
              task(currentMsg);
            }
          }
          if (!key.reset()) {
            break;
          }
        }
      } catch (Exception e) {
        logger.error("watch file error", e);
      }
    }
  }

  private static void task(MessageInfo messageInfo) {
    // 取消之前的 延时任务
    if (timer != null) {
      timer.cancel();
    }

    SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    try {
      startTime = dateFormat.parse(messageInfo.getStartTime());
      endTime = dateFormat.parse(messageInfo.getEndTime());
    } catch (ParseException e) {
      logger.error("时间转换错误", e);
    }

    // 判断 开始时间 和 结束时间 是否 合法
    if (startTime != null && endTime != null &&
            (endTime.getTime() - startTime.getTime()) > 0) {
      Date now = new Date();
      long l = startTime.getTime() - now.getTime();

      // 有效的开始时间
      if (l > 0 && currentMsg.isPublic()) {
        timer = new Timer();
        timer.schedule(new TimerTask() {
          @Override
          public void run() {
            sendMessageForAll(currentMsg);
            this.cancel();
          }
        }, l);
        logger.info("Set task success!：" + messageInfo.getStartTime() + "，content：" + currentMsg.getMsgContent());
      }
    }
  }

  // 获取 message Info 对象
  public static MessageInfo getMsgInfoByFile(File messageFile) {
    MessageInfo messageInfo = null;
    // 如果文件不为空
    if (messageFile != null) {

      BufferedReader reader = null;
      String content = "";
      try {
        FileInputStream fileInputStream = new FileInputStream(messageFile);
        reader = new BufferedReader(new InputStreamReader(fileInputStream, "UTF-8"));
        // 读取文件
        String valueString;
        while ((valueString = reader.readLine()) != null) {
          content += valueString;
        }
      }
      // 处理读取文件失败
      catch (Exception e) {
        logger.error("读取message.json文件失败", e);
      }
      // 关闭 reader
      finally {
        if (reader != null) {
          try {
            reader.close();
          } catch (Exception e) {
            logger.error("读取message.json文件失败", e);
          }
        }
      }
      if (!StringUtils.isEmpty(content)) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
          messageInfo = objectMapper.readValue(content, MessageInfo.class);
        } catch (IOException e) {
          logger.error("读取message.json文件失败", e);
        }
      }
    }
    return messageInfo;
  }

  // 获取 message file 对象
  public static File getMessageFile() {
    Resource resource = new ClassPathResource("message.json");
    File file = null;
    try {
      file = resource.getFile();
    } catch (Exception e) {
      logger.error("读取message.json文件失败", e);
    }
    return file;
  }
}
